package com.ccys.doctor.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.ccys.common.third.aws.s3.S3Util;
import com.ccys.common.third.push.firebase.FireBaseUtil;
import com.ccys.common.third.push.huawei.HuaWeiPush;
import com.ccys.common.third.push.huawei.push.exception.HuaweiMesssagingException;
import com.ccys.common.third.push.ios.IosNotificationUtil;
import com.ccys.common.vo.ResponseResultApp;
import com.ccys.db.cache.UserUtil;
import com.ccys.db.dto.doctor.constant.PushNotificationConstant;
import com.ccys.db.dto.doctor.postConsult.*;
import com.ccys.db.entity.*;
import com.ccys.db.mapper.*;
import com.ccys.db.vo.doctor.postConsult.MemberDeviceInfoVo;
import com.ccys.doctor.service.*;
import com.google.firebase.messaging.FirebaseMessagingException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * @Author：XLY
 * @Date：2024/2/7 0007
 */
@Service
@Slf4j
public class PostConsultServiceImpl implements PostConsultService {


    @Resource
    private PDFDocumentService pdfDocumentService;

    @Resource
    private BookingSummaryService summaryService;

    @Resource
    private BookingImageService imageService;

    @Resource
    private TblBookingImageMapper bookingImageMapper;

    @Resource
    private BookingMemoService memoService;

    @Resource
    private TblBookingMemoMapper memoMapper;

    @Resource
    private TblMemberMapper memberMapper;


    @Resource
    private TblBookingReferralLetterMapper referralLetterMapper;


    @Resource
    private BookingReferralLetterService referralLetterService;

    @Resource
    private MemberSummaryService memberSummaryService;


    @Resource
    private BookingService bookingService;


    @Resource
    private TblMemberPushNotificationMapper pushNotificationMapper;





    /**
     * @param bookingId bookingId
     * @param imageName
     * @param imageType 1:Symptom的图片 2:MC的pdf 9:RL的pdf 10:receipt的pdf 12:MEMO的pdf 13:prescription的pdf
     */
    private void saveBookingImage(String bookingId, String imageName, Integer imageType) {
        // 添加记录到 tbl_booking_image
        // 1:Symptom的图片 2:MC的pdf 9:RL的pdf 10:receipt的pdf 12:MEMO的pdf 13:prescription的pdf
        String id = bookingImageMapper.getIdByBookingId(bookingId, imageType);
        TblBookingImage model = new TblBookingImage();
        model.setId(id);
        model.setImageType(imageType);
        model.setImageName(imageName);
        model.setBookingId(bookingId);
        imageService.insertOrUpdate(model);
    }

    /**
     * 根据传入的bookingId和imageType生成PDF
     *
     * @param bookingId bookingId
     * @param imageType 1:Symptom的图片 2:MC的pdf 9:RL的pdf 10:receipt的pdf 12:MEMO的pdf 13:prescription的pdf
     */
    private void generatePDF(String bookingId, Integer imageType) {
        TblBookingSummary summary = summaryService.findEntityById(bookingId);
        TblBooking booking = bookingService.findEntityById(bookingId);
        String consultationNo = booking.getConsultationNo();
        if(Objects.nonNull(summary)){
            byte[] bytes = null;
            String directory = "";
            String fileName = "";
            switch (imageType) {
                case 2:
                    bytes = pdfDocumentService.generateMedicalCertificatePdf(bookingId);
                    directory = "Consultation/MedicalCertificate";
                    fileName = summary.getMedicalCertificationCode()+".pdf";
                    break;
                case 9:
                    bytes = pdfDocumentService.generateReferralLetterPdf(bookingId);
                    directory = "Consultation/ReferralLetter/";
                    //查询referralLetterMapper看前面有几个，依次编号 ML16062326306867-A ML+code+ABC
                    Example example = new Example(TblBookingReferralLetter.class);
                    example.createCriteria().andEqualTo("delFlag",0)
                            .andEqualTo("bookingId",bookingId);
                    List<TblBookingReferralLetter> referralLetters = referralLetterMapper.selectByExample(example);
                    char c = 'A'; // 要加的字母
                    int n = CollectionUtils.isNotEmpty(referralLetters)?referralLetters.size():0; // 要加的数字
                    char result = (char)(c + n); // 加法运算，并将结果转换为字符类型
                    fileName = "ML"+consultationNo+"-"+result+".pdf";
                    break;
                case 10:
                    break;
                case 12:
                    bytes = pdfDocumentService.generateMemoPdf(bookingId);
                    directory ="Consultation/Memo/";
                    //memo-0511030263842.pdf
                    fileName = "memo-"+consultationNo+".pdf";
                    break;
                case 13:
                    break;
                default:
                    break;

            }
            if (Objects.nonNull(bytes)) {
                S3Util.putS3ObjectByByte("",directory+fileName,bytes);
                // 1:Symptom的图片 2:MC的pdf 9:RL的pdf 10:receipt的pdf 12:MEMO的pdf 13:prescription的pdf
                saveBookingImage(bookingId, fileName, imageType);
            }
        }
    }

    @Override
    public ResponseResultApp generateMedicalCertificate(GenerateMedicalCertificateDto dto) {
        String bookingId = dto.getBooking_id();
        generatePDF(bookingId, 2);
        return ResponseResultApp.success();
    }

    @Override
    @Transactional
    public ResponseResultApp generateMemo(GenerateMemoDto dto) {
        String bookingId = dto.getBooking_id();
        generatePDF(bookingId, 12);
        return ResponseResultApp.success();
    }

    @Override
    public ResponseResultApp generateReferralLetter(GenerateReferralLetterDto dto) {
        // 得到pdf的byte数组
        String bookingId = dto.getBooking_id();
        generatePDF(bookingId, 9);
        return ResponseResultApp.success();
    }

    @Override
    public ResponseResultApp updateMemberSummary(UpdateMemberSummaryDto dto) {

        //更新tbl_member_summary数据
        TblMemberSummary summary = new TblMemberSummary();
        summary.setId(dto.getId());
        summary.setBody(dto.getBody());
        summary.setBody(dto.getBody());
        String curLoginUserId = UserUtil.getCurLoginUserId();
        summary.setDoctorId(curLoginUserId);
        memberSummaryService.insertOrUpdate(summary);
        return ResponseResultApp.success();
    }


    @Override
    @Transactional
    public ResponseResultApp updateMemo(UpdateMemoDto dto) {
        // 1、上传memo附件到consult_note文件夹下面
        List<UpdateMemoDto.AttachFileVo> attached_files = dto.getAttached_files();
        attached_files.forEach(x -> {
            byte[] file_byte = x.getFile_byte();
            //这个file_name是单纯的file_name不包含directory
            String file_name = x.getFile_name();
            String file_path = x.getFile_path();
            if (StringUtils.isEmpty(file_path)) {
                //上传到指定的文件夹下面
                //memo的路径是Consultation/Memo/
                S3Util.putS3ObjectByByte("", "Consultation/Memo/" + file_name, file_byte);
            } else if (file_path.contains(file_name)) {
                //得到这个file的byte[]
                //再上传一遍
                byte[] resultPDF = S3Util.getObjectBytes("", file_path);
                S3Util.putS3ObjectByByte("", "Consultation/Memo/" + file_name, resultPDF);
            }
        });
        //2、修改Booking的show_memo以及memo信息，
        TblBookingSummary summary = new TblBookingSummary();
        String memo = dto.getMemo();
        summary.setMemo(memo);
        Integer show_memo = dto.getShow_memo();
        summary.setShowMemo(show_memo);
        String booking_id = dto.getBooking_id();
        summary.setId(booking_id);
        summaryService.insertOrUpdate(summary);

        if (CollectionUtils.isNotEmpty(attached_files)) {
            //先根据Bookingid删除memo附件信息
            memoMapper.deleteByBookingId(booking_id);
            //然后批量添加tbl_booking_memo附件信息
            List<TblBookingMemo> collect = attached_files.stream().map(x -> {
                TblBookingMemo model = new TblBookingMemo();
                model.setId(IdUtil.getSnowflakeNextIdStr());
                model.setBookingId(booking_id);
                model.setMemoFileName(x.getFile_name());
                return model;
            }).collect(Collectors.toList());
            memoService.insertAll(collect);
        }
        //如果show_memo = 1 and memo is not null 从member查询deviceId和devicetype出来，发送通知给病人
        if (Objects.nonNull(show_memo) && show_memo == 1 && StringUtils.isNotEmpty(memo)) {
            // Constants.API_Notification_Type.PATIENT.MEMO_IS_UPDATED = 16
            // Message.NOTIFICATION_UPDATE_MEMO
            // Message = Your consultation memo has been updated. Tap this notification to view.
            saveAndPushNotification(booking_id, PushNotificationConstant.MEMO_IS_UPDATED,PushNotificationConstant.NOTIFICATION_UPDATE_MEMO);

        }

        return ResponseResultApp.success();
    }


    public void saveAndPushNotification(String bookingId,Integer pushType,String title){
        MemberDeviceInfoVo memberDeviceInfoVo = memberMapper.getDeviceInfoByBookingId(bookingId);
        String body = "";
        String deviceId = memberDeviceInfoVo.getDeviceId();
        Integer deviceType = memberDeviceInfoVo.getDeviceType();
        if(StringUtils.isNotEmpty(deviceId)&& Objects.nonNull(deviceType)){
            //3、 新开线程去 PushNotification
            CompletableFuture.runAsync(()->{
                //pushNotification
                List<String> tokenList = Lists.newArrayList();
                tokenList.add(deviceId);
                switch (deviceType){
                    case 1:
                        IosNotificationUtil.push(tokenList,title,body,true,null);
                        break;
                    case 2:
                        try {
                            FireBaseUtil.pushMulti(tokenList,title,body);
                        } catch (FirebaseMessagingException e) {
                            log.error(e.getMessage());
                        }
                        break;
                    case 3:
                        try {
                            HuaWeiPush.pushToByToken(title,body,"",tokenList);
                        } catch (HuaweiMesssagingException e) {
                            log.error(e.getMessage());
                        }
                        break;
                    default:
                        break;
                }
                //SaveNotification
                TblMemberPushNotification pushNotification = new TblMemberPushNotification();
                pushNotification.setBookingId(bookingId);
                pushNotification.setPushType(pushType);
                pushNotification.setIsRead(0);
                pushNotification.setMemId(memberDeviceInfoVo.getId());
                pushNotification.setPushOn(new Date());
                pushNotification.setPushMessage(title);
                pushNotification.setObjectId(bookingId);
                pushNotificationMapper.insert(pushNotification);
            });
        }

    }

    @Override
    public ResponseResultApp updateReferralLetter(UpdateReferralLetterDto dto) {
        String booking_id = dto.getBooking_id();
        List<UpdateReferralLetterDto.ReferralLetterVo> referral_letters = dto.getReferral_letters();
        //1、修改Booking的needReferralLetter
        if (CollectionUtils.isNotEmpty(referral_letters) && StringUtils.isNotEmpty(booking_id)) {
            //2、删除之前的booking_referral_letter ,批量添加新的
            referralLetterMapper.deleteByBookingId(booking_id);
            List<TblBookingReferralLetter> collect = referral_letters.stream().map(x -> {
                TblBookingReferralLetter model = new TblBookingReferralLetter();
                model.setReferralLetterCode(x.getReferral_letter_code());
                model.setReferralLetterText(x.getReferral_letter_text());
                model.setBookingId(booking_id);
                model.setSpecialistId(x.getSpecialist_id());
                model.setSpecialisationId(x.getMDST_ID());
                model.setId(IdUtil.getSnowflakeNextIdStr());
                return model;
            }).collect(Collectors.toList());
            referralLetterService.insertAll(collect);
            // 3、新开线程去PushNotification
            // string message = "Your referral letter has been updated. Tap this notification to view.";
            // MEDICAL_LETTER_IS_UPDATED = 20;
            saveAndPushNotification(booking_id,PushNotificationConstant.MEDICAL_LETTER_IS_UPDATED,PushNotificationConstant.NOTIFICATION_UPDATE_REFERRAL_LETTER);

        }
        return ResponseResultApp.success();
    }

    @Override
    public ResponseResultApp updateShowMemo(UpdateShowMemoDto dto) {
        //1、更新show_memo这个字段
        String bookingId = dto.getBooking_id();
        TblBookingSummary summary = new TblBookingSummary();
        summary.setId(bookingId);
        summary.setShowMemo(dto.getShow_memo());
        //2、新开线程去PushNotification
        saveAndPushNotification(bookingId, PushNotificationConstant.MEMO_IS_UPDATED,PushNotificationConstant.NOTIFICATION_UPDATE_MEMO);
        return ResponseResultApp.success();
    }

    @Override
    @Transactional
    public ResponseResultApp updateBookingMedicalCertificate(UpdateBookingMedicalCertificateDto dto) {
        String bookingId = dto.getBooking_id();
        TblBooking bookingEntity = bookingService.findEntityById(bookingId);
        TblBookingSummary summaryEntity = summaryService.findEntityById(bookingId);
        //doctor要是这个booking的doctor才可以改
        if (Objects.nonNull(bookingEntity) && Objects.nonNull(summaryEntity)) {
            Integer status = bookingEntity.getStatus();
            if (Objects.nonNull(status) && status != -1 && status < 4) {
                TblBooking booking = new TblBooking();
                booking.setId(bookingId);
                booking.setStatus(4);
                bookingService.insertOrUpdate(booking);
            }

            Integer isDelete = dto.getIsDelete();
            boolean flag = Objects.nonNull(isDelete) && isDelete == 1;
            TblBookingSummary summary = new TblBookingSummary();
            summary.setId(bookingId);
            summary.setMedicalCertificationCode(flag ? "" : "MC" + bookingEntity.getConsultationNo());
            summary.setMedicalCertificationBeginDate(flag ? null : DateUtil.parseDate(dto.getMedical_certification_begin_date()));
            summary.setMedicalCertificationEndDate(flag ? null : DateUtil.parseDate(dto.getMedical_certification_end_date()));
            summary.setAdditionalNote(flag ? "" : dto.getMedical_certification_additional_note());
            summary.setNeedMedicalCertification(flag ? 0 : 1);
            summaryService.insertOrUpdate(summary);
        }
        //新开线程去PushNotification
        saveAndPushNotification(bookingId,PushNotificationConstant.MEDICAL_CERTIFICATE_IS_UPDATED,PushNotificationConstant.NOTIFICATION_UPDATE_MEDICAL_CERTIFICATE);
        return ResponseResultApp.success();
    }

    @Override
    public ResponseResultApp updateBookingMedicalLetter(UpdateBookingMedicalLetterDto dto) {

        TblBookingSummary summary = new TblBookingSummary();
        String bookingId = dto.getBooking_id();
        Integer isDelete = dto.getIsDelete();
        boolean flag = Objects.nonNull(isDelete) && isDelete == 1;
        summary.setBookingId(bookingId);
        summary.setNeedMedicalLetter(flag ? 0 : 1);
        summaryService.insertOrUpdate(summary);
        // 新开线程去PushNotification
        saveAndPushNotification(bookingId,PushNotificationConstant.MEDICAL_LETTER_IS_UPDATED,PushNotificationConstant.NOTIFICATION_UPDATE_REFERRAL_LETTER);
        return ResponseResultApp.success();
    }



}
